/* -*-C-*-
 ##############################################################################
 #
 # File:        trice/src/testintr.c
 # RCS:         "@(#)$Revision: 1.22 $ $Date: 94/03/15 17:05:12 $"
 # Description: User routine for doing self test of E1430 module interrupts
 # Author:      Doug Passey
 # Created:     
 # Language:    C
 # Package:     E1430
 # Status:      "@(#)$State: Exp $"
 #
 # (C) Copyright 1992, Hewlett-Packard Company, all rights reserved.
 #
 ##############################################################################
 #
 # Please add additional comments here
 #
 # Revisions:
 #
 ##############################################################################
*/

#    include <stdio.h>
#    include <math.h>
#    ifndef EMULATE_SICL
#      include <sicl.h>
#    endif

#include "trice.h"
#include "err1430.h"

#ifndef lint
const char i1430_testintr_fileId[] = "$Header: testintr.c,v 1.22 94/03/15 17:05:12 chriss Exp $";
#endif



#ifdef DOS_OS
#pragma check_stack (off)
#endif

#ifndef EMULATE_SICL
  /* The intrrupt tests are skipped when emulating SICL */

/*****************************************************************************
 *
 * Interrupt handler
 *
 ****************************************************************************/

static void intr_handler(INST id, LONGSIZ32 reason, LONGSIZ32 sec)
  {
    e1430_intr_occurred = 1;
    e1430_intr_status = (SHORTSIZ16)sec;
    e1430_intr_status &= 0xCFFF;		/* mask off ADC_ERROR, ADC_OVERLOAD */
  }



/*****************************************************************************
 *
 * Kill some time waiting for interrupt to happen
 *
 ****************************************************************************/
static void kill_time(void)
{
  SHORTSIZ16 j;

  for(j=0; j<100; j++) {
    j++;
  }
}
#endif 		/* EMULATE_SICL */

/*****************************************************************************
 *
 * Run interrupt diagnostics
 *
 ****************************************************************************/
SHORTSIZ16 e1430_test_interrupts(SHORTSIZ16 la)
{

#ifndef EMULATE_SICL 
    /* this test is skipped when emulating SICL */

  ULONGSIZ32 host_la;
  SHORTSIZ16 error, reg, mask, i, j, maxIntrLines, statusMask;
  LONGSIZ32 lerror;
  char buf1[80];
  char buf2[80];
  SHORTSIZ16 intrLines[8];

  /* need to open both an interface and a device session and install 
   * handlers for both; so we can handle interrupts in the case we are 
   * operating in the E1485 environment and the E1430 is either in or
   * not in the servant list of the E1485.  Don't try to figure it out ....
   * just don't muck with this first part of the code ... it works
   */
  INST device_id, interface_id;
  struct vxiinfo info;

  (void)sprintf(buf1, "vxi");


  interface_id = iopen(buf1);
  if(!interface_id) {
    return(i1430_Error(ERR1430_UNABLE_TO_OPEN_SICL, buf1, NULL));
  }

  (void)sprintf(buf1, "vxi,%d", (LONGSIZ32)la);

  device_id= iopen(buf1);	/* may fail if not servant */

  lerror = ivxibusstatus(interface_id, I_VXI_BUS_LADDR, &host_la);
  if(lerror) {
      return(i1430_Error(ERR1430_TRIG_LINE_STATE, NULL, NULL));
  }

  /* get which interrupt lines we can interrupt on.  info.int_handler[]
   * is an array of the interrupt priorities(lines) that can be handled by the
   * device running this library.  It is terminated by a -1.
   */
  lerror = ivxirminfo(interface_id, (SHORTSIZ16)host_la, &info);
  if(lerror) {
      return(i1430_Error(ERR1430_VXI_INFO, NULL, NULL));
  }

  for(maxIntrLines = 0; maxIntrLines<8; maxIntrLines++) {
    if(info.int_handler[maxIntrLines] == -1) break;
  }

  if(maxIntrLines == 0) {	/* need at least one interrupt */
    return(i1430_Error(ERR1430_NO_INTR_LINES, buf1, NULL));
  }

  for(i=0; i<maxIntrLines; i++) {
    intrLines[i] = info.int_handler[i];
  }

  /* install interrupt handler */
  lerror = ionintr(interface_id, intr_handler);
  if(lerror) {
    return(i1430_Error(ERR1430_INTERRUPT_INSTALL, buf1, NULL));
  }

  if(device_id) {
    lerror = ionintr(device_id, intr_handler);
    if(lerror) {
      return(i1430_Error(ERR1430_INTERRUPT_INSTALL, buf1, NULL));
    }
  }

  /* enable interrupt handler */
  lerror = isetintr(interface_id, I_INTR_VXI_VME, 1);
  if(lerror) {
    return(i1430_Error(ERR1430_INTERRUPT_ENABLE, NULL, NULL));
  }

  if(device_id) {
    lerror = isetintr(device_id, I_INTR_VXI_SIGNAL, 1);
    if(lerror) {
      return(i1430_Error(ERR1430_INTERRUPT_ENABLE, NULL, NULL));
    }
  }

  error = e1430_hard_reset(la);
  if(error) return(error);

  error = i1430_reset_E1430(la);
  if(error) return(error);

  error = e1430_write_register_card(la, E1430_TRIGGER_SETUP_REG,
				TRIGGER_SETUP_TRIG_AUTO_OFF);
  if(error) return(error);

  /* clear interrupt masks for both interrupts */
  error = e1430_write_register_card(la, E1430_IRQ_CONFIG_0_REG, 0);
  if(error) return(error);

  error = e1430_write_register_card(la, E1430_IRQ_CONFIG_1_REG, 0);
  if(error) return(error);

  (void)sprintf(buf1, "%d", (LONGSIZ32)la);

  e1430_intr_occurred = 0; /* initialize e1430_intr_occurred */

  /* arm module */

  error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE);
  if(error) return(error);

  error = i1430_pull_sync(la, MEAS_CONTROL_NORMAL_MODE);
  if(error) return(error);

  error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE);
  if(error) return(error);


  /* check to make sure no interrupts occur if the arm bit is not set */
  mask = IRQ_CONFIG_READ_VALID | IRQ_CONFIG_BLOCK_READY | IRQ_CONFIG_MEAS_DONE;

  for(j=0; j<2; j++) {		/* for both interupt generators */
    reg = j ? E1430_IRQ_CONFIG_1_REG : E1430_IRQ_CONFIG_0_REG;

    for(i=0; i<maxIntrLines; i++) {
      error = e1430_write_register_card(la, reg, mask + intrLines[i]);
      if(error) return(error);
    
      kill_time();		/* kill some time */

      if(e1430_intr_occurred) {	/* if erroneous interrupt */
        (void)sprintf(buf1, "%d", (LONGSIZ32)intrLines[i]);
        (void)sprintf(buf2, "%d", (LONGSIZ32)j);
        return(i1430_Error(ERR1430_UNEXPECTED_INTERRUPT, buf1, buf2));
      }
    }
  }

  /* now mask for ARMED interrupt and check to see if we get it 
   * for all allowed interrupt priorities 
   */
  mask = IRQ_CONFIG_ARMED;
  statusMask = IRQ_CONFIG_ARMED | E1430_MEAS_STATUS_MODID + la;

  for(j=0; j<2; j++) {		/* for both interupt generators */
    reg = j ? E1430_IRQ_CONFIG_1_REG : E1430_IRQ_CONFIG_0_REG;

    for(i=0; i<maxIntrLines; i++) {
      error = e1430_write_register_card(la, reg, mask + intrLines[i]);
      if(error) return(error);

      kill_time();		/* kill some time */

      if(!e1430_intr_occurred) {	/* if no interrupt */
        (void)sprintf(buf1, "%d", (LONGSIZ32)intrLines[i]);
        (void)sprintf(buf2, "%d", (LONGSIZ32)j);
        return(i1430_Error(ERR1430_MISSING_ARMED_INTR, buf1, buf2));
      }else{
	if(e1430_intr_status != statusMask) {
	  (void)sprintf(buf1, "0x%X", (LONGSIZ32)statusMask);
	  (void)sprintf(buf2, "0x%X", (LONGSIZ32)e1430_intr_status);
          return(i1430_Error(ERR1430_WRONG_INTR_STATUS, buf1, buf2));
	}
      }
      e1430_intr_occurred = 0;
    }
  }

  /* finish measurement loop to set MEAS_DONE, BLOCK_READY and READ_VALID
   * bits in status register
   */

  error = i1430_pull_sync(la, MEAS_CONTROL_NORMAL_MODE);
  if(error) return(error);

  error = i1430_release_sync(la, MEAS_CONTROL_NORMAL_MODE);
  if(error) return(error);

  error = i1430_wait_for_block_ready_la(la, &reg);
  if(error) {
    if(-1 == error) {		/* device_clear from SCPI */
      (void)e1430_abort_meas(e1430_groupID);
      return(0);
    }else{
      return(error);
    }
  }

  statusMask = IRQ_CONFIG_READ_VALID | IRQ_CONFIG_BLOCK_READY |
		IRQ_CONFIG_MEAS_DONE | E1430_MEAS_STATUS_MODID + la;

  /* now mask for READ_VALID interrupt and check to see if we get it */
  mask = IRQ_CONFIG_READ_VALID;

  /* for both interupt generators */
  for(j=0; j<2; j++) {
    reg = j ? E1430_IRQ_CONFIG_1_REG : E1430_IRQ_CONFIG_0_REG;

    error = e1430_write_register_card(la, reg, mask + intrLines[0]);
    if(error) return(error);
    
    kill_time();		/* kill some time */

    if(!e1430_intr_occurred) {	/* if no interrupt */
      (void)sprintf(buf1, "%d", (LONGSIZ32)intrLines[0]);
      (void)sprintf(buf2, "%d", (LONGSIZ32)j);
      return(i1430_Error(ERR1430_MISSING_READ_VALID_INTR, buf1, buf2));
    }else{
      if(e1430_intr_status != statusMask) {
        (void)sprintf(buf1, "0x%X", (LONGSIZ32)statusMask);
        (void)sprintf(buf2, "0x%X", (LONGSIZ32)e1430_intr_status);
        return(i1430_Error(ERR1430_WRONG_INTR_STATUS, buf1, buf2));
      }
    }
    e1430_intr_occurred = 0;
  }

  /* now mask for BLOCK_READY interrupt and check to see if we get it */
  mask = IRQ_CONFIG_BLOCK_READY;

  /* for both interupt generators */
  for(j=0; j<2; j++) {
    reg = j ? E1430_IRQ_CONFIG_1_REG : E1430_IRQ_CONFIG_0_REG;

    error = e1430_write_register_card(la, reg, mask + intrLines[0]);
    if(error) return(error);
    
    kill_time();		/* kill some time */

    if(!e1430_intr_occurred) {	/* if no interrupt */
      (void)sprintf(buf1, "%d", (LONGSIZ32)intrLines[0]);
      (void)sprintf(buf2, "%d", (LONGSIZ32)j);
      return(i1430_Error(ERR1430_MISSING_BLOCK_READY_INTR, buf1, buf2));
    }else{
      if(e1430_intr_status != statusMask) {
        (void)sprintf(buf1, "0x%X", (LONGSIZ32)statusMask);
        (void)sprintf(buf2, "0x%X", (LONGSIZ32)e1430_intr_status);
        return(i1430_Error(ERR1430_WRONG_INTR_STATUS, buf1, buf2));
      }
    }
    e1430_intr_occurred = 0;
  }

  /* now mask for MEAS_DONE interrupt and check to see if we get it */
  mask = IRQ_CONFIG_MEAS_DONE;

  /* for both interupt generators */
  for(j=0; j<2; j++) {
    reg = j ? E1430_IRQ_CONFIG_1_REG : E1430_IRQ_CONFIG_0_REG;

    error = e1430_write_register_card(la, reg, mask + intrLines[0]);
    if(error) return(error);
    
    kill_time();		/* kill some time */

    if(!e1430_intr_occurred) {	/* if no interrupt */
      (void)sprintf(buf1, "%d", (LONGSIZ32)intrLines[0]);
      (void)sprintf(buf2, "%d", (LONGSIZ32)j);
      return(i1430_Error(ERR1430_MISSING_MEAS_DONE_INTR, buf1, buf2));
    }else{
      if(e1430_intr_status != statusMask) {
        (void)sprintf(buf1, "0x%X", (LONGSIZ32)statusMask);
        (void)sprintf(buf2, "0x%X", (LONGSIZ32)e1430_intr_status);
        return(i1430_Error(ERR1430_WRONG_INTR_STATUS, buf1, buf2));
      }
    }
    e1430_intr_occurred = 0;
  }

  (void)ionintr(interface_id, 0);

  if(device_id) {
    (void)ionintr(device_id, 0);
  }

  /* disable interrupt handler */
  (void)isetintr(interface_id, I_INTR_VXI_VME, 0);

  if(device_id) {
    (void)isetintr(device_id, I_INTR_VXI_SIGNAL, 0);
  }

  iclose(interface_id);
  if(device_id) iclose(device_id);

#endif    /* EMULATE_SICL */

  return (0);
}
